package cn.xxm.ff.log.core.service;

import cn.xxm.ff.log.common.utils.DesensitizationHelper;
import cn.xxm.ff.log.common.utils.PropertyUtil;
import cn.xxm.ff.log.core.dto.CustomDesensitizeType;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;

import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static cn.xxm.ff.log.core.enums.DesensitizationTypeEnum.EmailKeyNames;


/**
 * Created by xuxiaoming005 on 2018-08-20.
 */
public class DesensitizationPolicyRegexImpl implements DesensitizationPolicy {

    @Override
    public Object[] desensitizeArgs(Object[] objs, Map<String, Set<String>> map, boolean stringKillSwitch) {
        return warpMessageArgs(objs, map, stringKillSwitch);
    }

    @Override
    public String desensitizeFormattedMessage(String formattedMessage, Map<String, Set<String>> map) {
        int beginIndex = formattedMessage.indexOf("{");
        int endIndex = formattedMessage.lastIndexOf("}");

        String substring = preHandleJsonString(formattedMessage, beginIndex, endIndex);
        // 消除循环引用
        substring = handleStringBeforeParse(substring);

        // 脱敏
        for (CustomDesensitizeType type: PropertyUtil.getTypeRetain().values()) {
            formattedMessage = this.desensitizeFields(
                    formattedMessage,
                    map.get(type.getType()),
                    type);
        }

        return formattedMessage;
    }

    /**
     * 预处理json字符串信息
     * @param formattedMessage 格式化的消息
     * @param beginIndex json字符串开始位置
     * @param endIndex json字符串结束位置
     * @return 处理过循环引用的json字符串
     */
    private String preHandleJsonString(String formattedMessage, int beginIndex, int endIndex) {
        String substring = formattedMessage.substring(beginIndex, endIndex + 1);
        if (StringUtils.contains(substring, "\\\"")) {
            substring = StringUtils.replace(substring, "\\\"", "\"");
        }

        substring = handleStringBeforeParse(substring);
        return substring;
    }

    /**
     * 对日志参数脱敏
     *
     * @param args
     * @return
     */

    private Object[] warpMessageArgs(Object[] args, Map<String, Set<String>> map, boolean stringKillSwitch) {

        Object[] result = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            Object o = args[i];
            String objStr = "";

            // 对string做json转换
            try {
                if (!(o instanceof String)) {
                    objStr = JSONObject.toJSONString(o);
                } else {
                    objStr = (String)o;
                }
            } catch (Exception e) {
                if (stringKillSwitch) {
                    result[i] = "************";
                } else {
                    result[i] = o;
                }
                continue;
            }

            if (StringUtils.isNotBlank(objStr)) {
                // 脱敏
                for (CustomDesensitizeType type: PropertyUtil.getTypeRetain().values()) {
                    objStr = this.desensitizeFields(
                            objStr,
                            map.get(type.getType()),
                            type);
                }
            }
            result[i] = objStr;
        }
        return result;
    }


    private String desensitizeFields(String oldMessage,
                                     Set<String> cardNames,
                                     CustomDesensitizeType type) {
        String newMsg = oldMessage;

        for (String field : cardNames) {
            String patterStr = buildPatternString(field.trim());
            Pattern pattern = Pattern.compile(patterStr);

            Matcher matcher = pattern.matcher(newMsg);

            while (matcher.find()) {
                String group = matcher.group();

                // 取值
                String[] keyVals = group.split(":");
                if (ArrayUtils.isEmpty(keyVals)
                        || keyVals.length != 2) {
                    break;
                }

                String replacement = "";
                // 数组
                if (StringUtils.contains(keyVals[1], "[")
                        && StringUtils.contains(keyVals[1], "]")) {
                    replacement = keyVals[1].trim().substring(1, keyVals[1].lastIndexOf("]"));
                    replacement = DesensitizationHelper.processArrayValue(replacement, type);
                } else if (StringUtils.contains(keyVals[1], "\"")){
                    replacement = DesensitizationHelper.processStringValue(keyVals[1], type);

                } else {
                    replacement = DesensitizationHelper.processNumberValue(keyVals[1], type);
                }

                // 处理结尾字符
                if (group.contains(",")) {
                    replacement += ",";
                }
                if (group.contains("}")) {
                    replacement += "}";
                }

                replacement = keyVals[0] + ":" + replacement;

                newMsg = matcher.replaceAll(replacement);
            }

        }

        return newMsg;
    }

    private static String getXinXin(int length) {
        StringBuffer strB = new StringBuffer();
        for (int i = 0; i < length; i++) {
            strB.append("*");
        }
        return strB.toString();
    }

    private static String handleStringBeforeParse(String input) {
        if (StringUtils.isBlank(input)) {
            return "";
        }

        String pattern1 = "\\{\"\\$ref\":\"[@\\$]\"\\}";
        String pattern2 = "\\{\"\\$ref\":\"(\\.){2}\"\\}";
        String pattern3 = "\\{\"\\$ref\":\"(\\$\\.children\\.\\d+)\"\\}";
        return input.replaceAll(pattern1, "null")
                .replaceAll(pattern2, "null")
                .replaceAll(pattern3, "null");
    }

    private static String processNumberValue(String val, CustomDesensitizeType type) {
        if (StringUtils.isBlank(val)) {
            return "";
        }

        return DesensitizationHelper.maskValue(val.trim(), type);
    }

    private static String processStringValue(String val, CustomDesensitizeType type) {
        if (StringUtils.isBlank(val)) {
            return "";
        }

        String valItem = val.trim();
        valItem = valItem.substring(1, valItem.lastIndexOf("\""));

        return "\"" + DesensitizationHelper.processNumberValue(valItem, type) + "\"";
    }



    private static String buildPatternString(String field) {
        String fieldName = "\"" + field + "\":";
        String fieldValue1 = "\"{1}([a-zA-z0-9@\\.\\-\\s\\:\\u4e00-\\u9fa5\"]{0,})\"{1}[\\,\\}]{1}";
        String fieldValue2 = "\\[{0,}((\\d,)*\\d)*\\]{0,}";
        String pattern = fieldName + fieldValue1 + "|" + fieldName +fieldValue2;

        return pattern;
    }

    public static void main(String[] args) {
        String targetString1 = "{\"email\":\"112233445566778899\",\"bindAccount\":\"112233445566778899\"}";
        String targetString2 = "{\"email\":\"1234567@qq.com\"}";
        String targetString3 = "{\"email\":1234567@qq.com,}";
        String targetString4 = "{\"email\":[1234567@qq.com,76543f2@qq.com]}";

        String fieldsStr = "email";
        String[] fields = fieldsStr.split(",");


        for (String field : fields) {
            String patterStr = buildPatternString(field.trim());
            Pattern pattern = Pattern.compile(patterStr);
            System.out.println("pattern: " + pattern);

            Matcher matcher = pattern.matcher(targetString2);
            StringBuffer stringBuffer = new StringBuffer();

            while (matcher.find()) {
                String group = matcher.group();
                System.out.println("group: " +group );

                // 取值
                String[] keyVals = group.split(":");
                String replacement = "";
                // 数组
                if (StringUtils.contains(keyVals[1], "[")) {
                    replacement = keyVals[1].trim().substring(1, keyVals[1].lastIndexOf("]"));
                    //replacement = processArrayValue(replacement);
                } else if (StringUtils.contains(keyVals[1], "\"")){
                    //replacement = processStringValue(keyVals[1]);
                    replacement = DesensitizationHelper.processStringValue(keyVals[1],
                            new CustomDesensitizeType(EmailKeyNames.getType(),
                                    EmailKeyNames.getStartIndex(),
                                    EmailKeyNames.getEndIndex())
                            );
                } else {
                    //replacement = processNumberValue(keyVals[1]);
                }

                if (group.contains(",")) {
                    replacement += ",";
                }
                if (group.contains("}")) {
                    replacement += "}";
                }

                replacement = keyVals[0] + ":" + replacement;
                System.out.println("replacement: " + replacement);

                targetString1 = matcher.replaceAll(replacement);
            }

            System.out.println(targetString1);
        }
    }

}
